import React, { memo, useRef } from 'react'
import { useSpring, animated } from '@react-spring/web'
import classNames from 'classnames'
import { warn } from '@/library/tool-kits/log'
import { NativeProps, withNativeProps } from '../../utils/native-props'
import { useLockScroll } from '../../hooks/use-lock-scroll'
import { useMotionReduced } from '../../utils/reduce-and-restore-motion'

const classPrefix = 'rt-spin-loading'

const circumference = 15 * 3.14159265358979 * 2

const colorRecord: Record<string, string> = {
  default: 'var(--rt-color-weak)',
  primary: 'var(--rt-color-primary)',
  white: 'var(--rt-color-text-light-solid)',
}

export type SpinLoadingProps = {
  /** 颜色. default: `default` */
  // eslint-disable-next-line @typescript-eslint/ban-types
  color?: 'default' | 'primary' | 'white' | (string & {})
  /** 是否铺满整个屏幕. default: `false` */
  fullScreen?: boolean
  /** 是否设置为 `block`. default: `false` */
  block?: boolean
  /** loading (`fullScreen === true`的情况下使用). default: `false` */
  loading?: boolean
  /** children. 仅在(`fullScreem === true`)是渲染 */
  children?: React.ReactNode
} & NativeProps<
  /** 线条颜色. default: 'var(--rt-color-weak)' */
  | '--color'
  /** 大小. default: `20px` */
  | '--size'
>

export const SpinLoading = memo<SpinLoadingProps>((props) => {
  const {
    color = 'default',
    fullScreen = false,
    block = false,
    loading = false,
    children,
  } = props

  const motionReduced = useMotionReduced()

  const ref = useRef<HTMLDivElement>(null)

  useLockScroll(ref, fullScreen && loading)

  const { percent } = useSpring({
    cancel: motionReduced,
    loop: {
      reverse: true,
    },
    from: {
      percent: 80,
    },
    to: {
      percent: 30,
    },
    config: {
      duration: 1200,
    },
  })

  if (!fullScreen && children) {
    warn(
      'SpinLoading',
      'SpinLoading props fullScreen is `false`, So the component can\'t render `children` prop.',
    )

    return
  }

  if (fullScreen && !children) {
    warn(
      'SpinLoading',
      'SpinLoading props fullScreen is `true`, you can provide `children` prop to render.',
    )
  }

  if (fullScreen && !loading) return children as React.ReactElement
  // 未开启全屏模式不允许渲染children. 开启全屏模式且开启loading, 渲染children
  return withNativeProps(
    props,
    <div
      ref={ref}
      className={classNames(classPrefix, block && `${classPrefix}-block`, fullScreen && loading && `${classPrefix}-full`)}
      style={{ '--color': colorRecord[color] ?? color } as any}
    >
      <animated.div className={`${classPrefix}-inner`}>
        <svg className={`${classPrefix}-svg`} viewBox="0 0 32 32">
          <animated.circle
            className={`${classPrefix}-fill`}
            fill="transparent"
            strokeWidth="2"
            strokeDasharray={circumference}
            strokeDashoffset={percent}
            strokeLinecap="square"
            r={15}
            cx={16}
            cy={16}
          />
        </svg>
      </animated.div>
      {fullScreen && children}
    </div>,
  )
})
